﻿using ClassTableClient.DTO;
using ClassTableClient.Enum;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;

namespace ClassTableClient.Utils
{
    public class ClassServiceHelper
    {
        //项目路径
        static string[] path = Directory.GetCurrentDirectory().Split('\\');
        //项目名称
        static string nameSpace = path[path.Length - 1];


        /// <summary>
        /// 生成实体类cs文件 和 创建数据表的sql语句
        /// 可以生成多个实体类
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="properts">属性列表</param>
        /// <param name="serverType">数据库类型</param>
        /// <param name="sql">返回参数：生成的sql语句</param>
        /// <returns></returns>
        public static int CreateClassFileAndSql(string tableName, List<GenericClassDTO> properts, ServerTypeEnum serverType, out string sql)
        {
            sql = null;
            try
            {
                if (string.IsNullOrEmpty(tableName) && properts == null || properts.Count <= 0)
                {
                    return -1;
                }

                //属性信息
                Dictionary<string, string> propertKeyValue = new Dictionary<string, string>();
                //创建表sql语句

                //实例化一个可变字符串用于拼接生成的实体类信息
                StringBuilder stringBuilder = new StringBuilder();

                //默认命名空间为项目名称，把实体类生成到项目目录中
                stringBuilder.AppendLine($"using System;");
                stringBuilder.AppendLine($"");
                stringBuilder.AppendLine($"namespace {nameSpace}");
                stringBuilder.AppendLine("{");
                stringBuilder.AppendLine($"    public class {tableName}");
                stringBuilder.AppendLine("    {");
                foreach (var propert in properts)
                {
                    stringBuilder.AppendLine("        /// <summary>");
                    stringBuilder.AppendLine($"        /// {propert.PropertRemark}");
                    stringBuilder.AppendLine("        /// <summary>");
                    stringBuilder.AppendLine($"        public {propert.PropertType} {propert.PropertName} {{ get;set; }}");
                    stringBuilder.AppendLine();

                    //属性值信息
                    propertKeyValue.Add(propert.PropertName, propert.PropertType);
                }
                stringBuilder.AppendLine("    }");
                stringBuilder.AppendLine("}");

                //该文件的输出路径
                string outputPath = Directory.GetCurrentDirectory() + "\\Model\\" + tableName + ".cs";
                System.IO.File.AppendAllText(outputPath, stringBuilder.ToString());

                //sql语句拼接
                sql = SqlJoin(propertKeyValue, tableName, serverType);
            }
            catch (Exception ex)
            {
                Console.WriteLine("生成实体类cs文件异常：" + ex.Message);
                return -2;
            }
            return 200;
        }


        /// <summary>
        /// Sql语句拼接
        /// </summary>
        /// <param name="data">属性-类型 字典</param>
        /// <param name="tableName">实体类名-表名</param>
        /// <param name="serverType">数据库类型</param>
        /// <returns>创建数据库:表、字段的SQL语句</returns>
        public static string SqlJoin(Dictionary<string, string> data, string tableName, ServerTypeEnum serverType)
        {
            //sql语句
            string sql = string.Empty;
            //主键属性
            string PrimaryKey = string.Empty;
            //是否是第一个字段
            bool isFirst = true;

            switch (serverType)
            {
                case ServerTypeEnum.MySql:  //MySql数据库
                    //拼接表名
                    sql += $"DROP TABLE IF EXISTS `{tableName}`; " +
                        $"CREATE TABLE `{tableName}`(";

                    //拼接字段
                    foreach (var item in data)
                    {
                        //是否是第一个字段,第一个字段默认主键
                        if (isFirst)
                        {
                            PrimaryKey = item.Key;
                            isFirst = false;
                        }

                        //数据库字段类型
                        string servicePropertType = VerifyPropertType(item.Value, ServerTypeEnum.MySql);

                        //判断属性类型是否识别
                        if (!string.IsNullOrEmpty(servicePropertType))
                        {
                            //识别，拼接sql
                            sql += $@"`{item.Key}` {servicePropertType},";
                        }
                        else
                        {
                            return "拥有未知类型!";
                        }
                    }

                    sql += $" PRIMARY KEY (`{PrimaryKey}`) USING BTREE);";

                    break;
                case ServerTypeEnum.SqlServer:  //SqlServer数据库
                    //拼接表名
                    sql += $"IF EXISTS (SELECT * FROM sys.databases WHERE name = '{tableName}'" +
                        $"DROP TABLE [dbo].[{tableName}] " +
                        $"CREATE TABLE [dbo].[{tableName}] (";

                    //拼接字段
                    foreach (var item in data)
                    {
                        //是否是第一个字段,第一个字段默认主键
                        if (isFirst)
                        {
                            PrimaryKey = item.Key;
                            isFirst = false;
                        }

                        //数据库字段类型
                        string servicePropertType = VerifyPropertType(item.Value, ServerTypeEnum.SqlServer);

                        //判断属性类型是否识别
                        if (!string.IsNullOrEmpty(servicePropertType))
                        {
                            //识别，拼接sql
                            sql += $@"[{item.Key}] {servicePropertType},";
                        }
                        else
                        {
                            return "拥有未知类型!";
                        }
                    }

                    sql += $" PRIMARY KEY ([{PrimaryKey}]));";

                    break;
                case ServerTypeEnum.Sqlite: //Sqlite
                    //拼接表名
                    sql += $"DROP TABLE IF EXISTS `{tableName}`; " +
                        $"CREATE TABLE `{tableName}` (";

                    //拼接字段
                    foreach (var item in data)
                    {
                        //数据库字段类型
                        string servicePropertType = VerifyPropertType(item.Value, ServerTypeEnum.Sqlite);

                        //是否是第一个字段,第一个字段默认主键
                        if (isFirst)
                        {
                            PrimaryKey = item.Key;
                            isFirst = false;
                            if (!string.IsNullOrEmpty(servicePropertType))
                            {
                                servicePropertType += " NOT NULL";
                            }
                        }

                        //判断属性类型是否识别
                        if (!string.IsNullOrEmpty(servicePropertType))
                        {
                            //识别，拼接sql
                            sql += $"`{item.Key}` {servicePropertType},";
                        }
                        else
                        {
                            return "拥有未知类型!";
                        }
                    }

                    sql += $" PRIMARY KEY (`{PrimaryKey}`));";

                    break;
                default:
                    return null;
            }
            return sql;
        }


        /// <summary>
        /// 校验字段类型
        /// </summary>
        /// <param name="type">数据类型</param>
        /// <param name="serverType">数据库类型</param>
        /// <returns>对应的数据库字段类型</returns>
        public static string VerifyPropertType(string type, ServerTypeEnum serverType)
        {
            string result = string.Empty;
            switch (serverType)
            {
                case ServerTypeEnum.MySql:
                    switch (type)
                    {
                        case "Int32":
                        case "int":
                        case "Boolean":
                        case "bool":
                            result = "int(0)";
                            break;
                        case "String":
                        case "string":
                            result = "varchar(255)";
                            break;
                        case "DateTime":
                        case "dateTime":
                            result = "datetime(0)";
                            break;
                        case "Double":
                        case "double":
                            result = "double";
                            break;
                    }
                    break;
                case ServerTypeEnum.SqlServer:
                    switch (type)
                    {
                        case "Int32":
                        case "int":
                        case "Boolean":
                        case "bool":
                            result = "int";
                            break;
                        case "String":
                        case "string":
                            result = "nvarchar(255)";
                            break;
                        case "DateTime":
                        case "dateTime":
                            result = "datetime";
                            break;
                        case "Double":
                        case "double":
                            result = "decimal(18)";
                            break;
                    }
                    break;
                case ServerTypeEnum.Sqlite:
                    switch (type)
                    {
                        case "Int32":
                        case "int":
                            result = "integer(2)";
                            break;
                        case "Boolean":
                        case "bool":
                            result = "integer(32)";
                            break;
                        case "String":
                        case "string":
                        case "DateTime":
                        case "dateTime":
                            result = "TEXT(40)";
                            break;
                        case "Double":
                        case "double":
                            result = "real(40)";
                            break;
                    }
                    break;
                default:
                    break;
            }
            return result;
        }

    }
}
